/*
 * find.c
 *
 *  Created on: Jun 15, 2014
 *      Author: eran
 */

#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"
#include "fs.h"

char buf[DIRSIZ];

//get last part of path. curname(a/b/c) = c
char*
curname(char *path){
	char *p;
	int len = strlen(path);
	buf[0] = '\0';
	if(!len)
		return buf;
	p = path + len - 1;
	while (*p !='/' && p > path)
		p--;
	if(*p == '/')
		p++;
	len = strlen(p);
	if (len > DIRSIZ)
		len = DIRSIZ;
	memmove(buf, p, len);
	buf[len] = '\0';
	return buf;
}

void
find(char *path,char *name, int ignore, char type, int size, int minmax)
{
	int fd;
	struct stat st;
	char *curnamev;
	char pathbuf[100];
	int len;
	struct dirent de;
	if ((fd  = open(path, O_IGNORE))== -1){
		printf(2, "Not a valid path\n");
		exit();
	}

	if(fstat(fd, &st) == -1){
		printf(2, "Unable to obtain file stats\n");
		exit();
	}

	// get file's name
	curnamev = curname(path);
	switch(st.type){
	case T_FILE:
		if (type != 'f' && type != ',')
			break;
		if (minmax != 2){
			if (minmax > 0 && st.size < size)
				break;
			if (minmax < 0 && st.size > size)
				break;
			if (minmax == 0 && st.size != size)
				break;
		}
		if (name && strcmp(name, curnamev) != 0)
			break;
		printf(1, "FOUND file: %s\n", path);
		break;
	case T_SYMLINK:
		if(ignore && (type == 's' || type == ','))
			if(!name || strcmp(name, curnamev) == 0)
				printf(1, "FOUND symbolic link: %s\n", path);
		if(!ignore){
			len = strlen(path);
			readlink(path, pathbuf + len, 100 - len);
			printf(1, "Descending to symbolic link: %s\n", curnamev);
			// If the link is referencing to root, send only the link. Otherwise, add it to current path
			if(pathbuf[len] == '/')
				find(pathbuf + len, name, ignore, type, size, minmax);
			else{
				memmove(pathbuf, path, len);
				find(pathbuf, name, ignore, type, size, minmax);
			}
		}
		break;
	case T_DIR:
		if(type == 'd' || type == ',')
			if(!name || strcmp(name, curnamev) == 0)
				printf(1, "FOUND directory: %s\n", path);
		len = strlen(path);
		memmove(pathbuf, path, len);
		while(read(fd, &de, sizeof(de))){
			if(de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..")==0)
				continue;
			if (*(pathbuf+len-1) != '/'){
				*(pathbuf+len) = '/';
				memmove(pathbuf + len +1, de.name, DIRSIZ);
			}
			else
				memmove(pathbuf + len, de.name, DIRSIZ);
			find(pathbuf, name, ignore, type, size, minmax);
		}

		break;
	}





	if(fd>-1)
		close(fd);
}

int
main(int argc, char *argv[])
{
	int i;
	int ignore = O_IGNORE;
	int size = -1;
	int minmax = 2; // 0 - exact size 1 - larger than -1 - smaller than
	int type = ',';
	char *path;
	char *name = 0;

	if(argc < 2){
		printf(2, "Not enough arguments.\nUsage: find <path> <options> <preds>\n<path> is required\n");
		exit();
	}
	path = argv[1];
	for(i = 2; i < argc; i++){
		if(strcmp(argv[i], "-help") == 0){
			printf(1, "Usage: find <path> <options> <preds>\n<path>\n starting pathname\n<options>\n  -follow\n    dereference symbolic links\n  -help\n    print a summary of find\n<preds>\n  -name filname\n    name of file to find\n  -size (+/-)n\n    files size n (n) more than n (+n) less than n (-n)\n  -type c\n    files of type c:\n      d - directory\n      f - regular file\n      s - symbolic link\n");
			exit();
		}
		if(strcmp(argv[i], "-follow") == 0){
			ignore = 0;
			continue;
		}
		if(strcmp(argv[i], "-name") == 0){
			if(++i == argc){
				printf(2, "Please specify file name\n");
				exit();
			}
			name = argv[i];
			continue;
		}
		if(strcmp(argv[i], "-size") == 0){
			char *tmpsize;

			if(++i == argc){
				printf(2, "Please specify file size\n");
				exit();
			}
			tmpsize = argv[i];
			switch(*tmpsize){
			case '+':
				minmax = 1;
				tmpsize++;
				break;
			case '-':
				minmax = -1;
				tmpsize++;
				break;
			default:
				minmax = 0;
				break;
			}
			size = atoi(tmpsize);
			continue;
		}
		if(strcmp(argv[i], "-type") == 0){
			if(++i == argc){
				printf(2, "Please specify file type\n");
				exit();
			}
			type = *argv[i];
			if((type != 'd') && (type != 'f') && (type != 's')){
				printf(2, "Not a valid file type (d/f/s required)\n");
				exit();
			}
		}
	}
	find(path, name, ignore, type, size, minmax);
	exit();


}
